package chen.web.stat;

import java.io.IOException;
import java.util.Date;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import chen.web.MyContext;
import chen.web.MyContextProvider;

public class StatisticsFilter implements Filter {
	public static final String StatIdAttributeName = "StatId";
	
	private static final String Header_User_Agent = "User-Agent";
	private static final String Header_Accept = "Accept";
	private static final String Header_Accept_Language = "AcceptLanguage";
	private static final String Header_Accept_Encoding = "Accept-Encoding";
	private static final String Header_Accept_Charset = "Accept-Charset";
	private static final String Header_Keep_Alive = "Keep-Alive";
	private static final String Header_Connection = "Connection";
	private static final String Header_Referer = "Referer";
	private static final String Header_Host = "Host";
	
	private static Log log = LogFactory.getLog(StatisticsFilter.class);
	
	@Override
	public void doFilter(ServletRequest req, ServletResponse res,
			FilterChain chain) throws IOException, ServletException {
		// TODO Auto-generated method stub
		long begin = System.currentTimeMillis();
		HttpServletRequest request = (HttpServletRequest)req;
		HttpServletResponse response = (HttpServletResponse)res;
		StatusExposingServletResponse wrapper = new StatusExposingServletResponse(response);
		RequestInfo info = getRequestInfo(request);
		int statId = Statistics.generalStatId();
		info.setId(statId);
		
		//request.setAttribute("statId", statId);
		MyContextProvider.getMyContext().setAttribute(StatIdAttributeName, statId);
		int status = -1;
		try{
			chain.doFilter(request, wrapper);
			status = wrapper.getStatus();
			//默认是200
			status = status == 0 ? 200 : status;
		}catch(RuntimeException ex){
			status = 500;
			throw ex;
		}finally{
			info.setResponseStatus(status);
			info.setProcessTime((int)(System.currentTimeMillis() - begin));
			try{
				Statistics.save(info);	
			}catch(Exception ex){
				log.error("存储请求信息出错: ",ex);
			}
			if(log.isDebugEnabled()){
				log.debug("储存请求信息: " + info.getRequestURL());
			}
		}
	}
	
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		Statistics.flush();
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub
		
	}
	
	private RequestInfo getRequestInfo(HttpServletRequest request){
		String userAgent = request.getHeader(Header_User_Agent);
		String accept = request.getHeader(Header_Accept);
		String acceptLanguage = request.getHeader(Header_Accept_Language);
		String acceptEncoding = request.getHeader(Header_Accept_Encoding);
		String acceptCharset = request.getHeader(Header_Accept_Charset);
		String keepAlive = request.getHeader(Header_Keep_Alive);
		String connection = request.getHeader(Header_Connection);
		String referer = request.getHeader(Header_Referer);
		String requestMethod = request.getMethod();
		String host = request.getHeader(Header_Host);
		String requestURL = getURL(request);
		
		MyContext context = MyContextProvider.getMyContext();

		RequestInfo info = new RequestInfo();
		info.setAccountId(context.getAccount().getId());
		info.setNickname(context.getAccount().getNickname());
		info.setAccept(accept);
		info.setAcceptCharset(acceptCharset);
		info.setAcceptEncoding(acceptEncoding);
		info.setAcceptLanguage(acceptLanguage);
		info.setConnection(connection);
		info.setKeepAlive(keepAlive);
		info.setReferer(referer);
		info.setRequestTime(new Date());
		info.setRequestURL(requestURL);
		info.setUserAgent(userAgent);
		info.setRequestMethod(requestMethod);
		info.setHost(host);
		info.setIp(context.getIp());
		info.setUuid(context.getUuid());
		return info;
	}
	
	private String getURL(HttpServletRequest request){
		StringBuffer sb = request.getRequestURL();
		String queryString  =request.getQueryString();
		if(queryString != null && queryString.length() > 0){
			sb.append('?').append(queryString);
		}
		return sb.toString();
	}
	
	
	private static class StatusExposingServletResponse extends HttpServletResponseWrapper {

	    private int httpStatus;

	    public StatusExposingServletResponse(HttpServletResponse response) {
	        super(response);
	    }

	    @Override
	    public void sendError(int sc) throws IOException {
	        httpStatus = sc;
	        super.sendError(sc);
	    }

	    @Override
	    public void sendError(int sc, String msg) throws IOException {
	        httpStatus = sc;
	        super.sendError(sc, msg);
	    }

	    @Override
		public void sendRedirect(String location) throws IOException {
			// TODO Auto-generated method stub
	    	httpStatus = 302;
			super.sendRedirect(location);
		}

		@Override
		public void setStatus(int sc, String sm) {
			// TODO Auto-generated method stub
			httpStatus = sc;
			super.setStatus(sc, sm);
		}

		@Override
	    public void setStatus(int sc) {
	        httpStatus = sc;
	        super.setStatus(sc);
	    }

	    public int getStatus() {
	        return httpStatus;
	    }

	}
}
